package org.liaohailong.victorlibrary.widget;

import android.content.Context;
import android.graphics.Rect;
import android.util.SparseArray;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

/**
 * Author: liaohailong
 * Date: 2019/5/11
 * Time: 9:15
 * Description: 学习一下自定义RecyclerView布局
 * 这是一个垂直方向的线性布局
 **/
public class LearnLayoutManager extends RecyclerView.LayoutManager {
    private Context context;
    private int scrollOffsetY = 0;
    private int totalHeight = 0;
    private SparseArray<Rect> viewRect = new SparseArray<>();

    public LearnLayoutManager(Context context) {
        this.context = context;
    }

    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT);
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        fill(recycler, state);
    }

    private void fill(RecyclerView.Recycler recycler, RecyclerView.State state) {
        //正在执行动画，或者其他原因导致尚未进入正式布局状态
        if (state.isPreLayout()) {
            return;
        }
        int visibleWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        int visibleHeight = getHeight() - getPaddingTop() - getPaddingBottom();

        if (getItemCount() <= 0 || visibleWidth <= 0 || visibleHeight <= 0) {
            removeAndRecycleAllViews(recycler);
            return;
        }

        int viewLayoutX = getPaddingLeft();
        int viewLayoutY = getPaddingTop() - scrollOffsetY;
        totalHeight = 0;

        //第一步，计算位置
        detachAndScrapAttachedViews(recycler);
        clearAllViewRect();
        for (int i = 0; i < getItemCount(); i++) {
            View scrapView = recycler.getViewForPosition(i);
            addView(scrapView);
            measureChildWithMargins(scrapView, 0, 0);
            int itemWidth = getDecoratedMeasuredWidth(scrapView);
            int itemHeight = getDecoratedMeasuredHeight(scrapView);

            //超出屏幕外的View不进行布局
            totalHeight += itemHeight;
            Rect rect = getViewRectByPosition(i);
            rect.set(viewLayoutX, viewLayoutY, viewLayoutX + itemWidth, viewLayoutY + itemHeight);
            viewLayoutY += itemHeight;
        }

        //第二部，布局
        detachAndScrapAttachedViews(recycler);
        Rect visibleRect = new Rect(
                getPaddingLeft(),
                getPaddingTop(),
                getWidth() - getPaddingRight(),
                getHeight() - getPaddingBottom());
        for (int i = 0; i < getItemCount(); i++) {
            Rect rect = getViewRectByPosition(i);
            //未测量View不进行布局
            if (rect.isEmpty()) {
                continue;
            }
            //在显示区域的View不进行布局
            if (isVisibleInArea(visibleRect, rect)) {
                View scrapView = recycler.getViewForPosition(i);
                addView(scrapView);
                layoutDecoratedWithMargins(scrapView, rect.left, rect.top, rect.right, rect.bottom);
            }
        }
    }

    private void clearAllViewRect() {
        for (int i = 0; i < viewRect.size(); i++) {
            int key = viewRect.keyAt(i);
            Rect rect = viewRect.get(key);
            if (rect != null) {
                rect.setEmpty();
            }
        }
    }

    private Rect getViewRectByPosition(int position) {
        Rect rect = viewRect.get(position);
        if (rect == null) {
            rect = new Rect();
            viewRect.put(position, rect);
        }
        return rect;
    }

    private boolean isVisibleInArea(Rect area, Rect item) {
        boolean isTopItemVisible = item.bottom > area.top;
        boolean isBottomItemVisible = item.top < area.bottom;
        boolean isLeftItemVisible = item.right > area.left;
        boolean isRightItemVisible = item.left < area.right;
        return isTopItemVisible || isBottomItemVisible || isLeftItemVisible || isRightItemVisible;
    }

    @Override
    public int computeVerticalScrollOffset(@NonNull RecyclerView.State state) {
        return scrollOffsetY;
    }

    @Override
    public int computeVerticalScrollRange(@NonNull RecyclerView.State state) {
        return totalHeight;
    }

    @Override
    public int computeVerticalScrollExtent(@NonNull RecyclerView.State state) {
        return getHeight();
    }

    @Override
    public boolean canScrollVertically() {
        return true;
    }

    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        //处理边界判断
        int realDy;
        //下滑判断，是否已经到顶部
        if (scrollOffsetY + dy <= 0) {
            scrollOffsetY = 0;
            realDy = 0;
        }
        //上滑判断，是否已经到底部
        else if (scrollOffsetY + dy >= totalHeight - getHeight()) {
            scrollOffsetY = totalHeight - getHeight();
            realDy = 0;
        }
        //正常可滑动区域
        else {
            scrollOffsetY += dy;
            realDy = dy;
        }
        fill(recycler, state);
        return realDy;
    }
}
